package com.dtx.qiku.sessionstore;

import com.dtx.qiku.store.FileStoreUtils;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

public class Session extends HashMap<String,Object> {

    /**
     * 记录 key 是否过期
     */
    private LocalDateTime expire;

    private SessionStore store ;

    /**
     * 设置一个唯一的编号
     */
    private String sessionId = UUID.randomUUID().toString();

    {
        store = new SessionStore(FileStoreUtils.getStore());
    }

    /**
     *  单例模式：
     *        1.私有化 构造方法（为了保证使用者不通过new 构建对象）
     *        2.提供一个 私有的 静态 属性（要构建的对象类型）
     *        3.提供一个 公开的 静态方法，返回需要的单例对象
     *            有可能需要做简单的逻辑判断
     *  单例模式：懒汉式 和 饿汉式 2种设计方式
     *
     *  懒汉式 ： 程序向对方要数据的时候，才尝试去创建该对象
     *          以时间换取空间：浪费时间，换取空间
     *  饿汉式 ： 无论对方是否需要该数据，都会先把需要的对象创建出来
     *          以空间换取时间：浪费空间，换取时间
     */

//    private static Session session = new Session();
//
//    public static Session getInstance(){
//        return session;
//    }

    private static Session session;

    // 懒汉式
    public static Session getInstance(){
        if (session == null){
            session = new Session();

        }

        return session;
    }


    /**
     * 控制 会话是否在 指定时间内 过期
     */
    private Session(){
        this(30 * 60);
    }

    private Session(int seconds){
        Duration duration = Duration.ofSeconds(seconds);
        this.expire =  LocalDateTime.now().plus(duration);

        // 将 sessionId 放入 map 中，作为键
        super.put("SESSIONID",sessionId);
    }

    /**
     * 使用 setAttribute 添加数据
     * @param key
     * @param value
     */
    public void setAttribute(String key, Object value) {

        if(!check()) throw new RuntimeException("Session已过期");

        // 调用父类方法，完成数据存储
        Object val = this.put(key,value);

        // 从仓库读取数据
        try {
            List<Session> list = store.read();

            if(list == null || list.isEmpty()){
                list = new ArrayList<>();
                // 将数据进行持久化
                list.add(this);
            }else {
                // 从 list 中，查找 对应的 session 是否存在

                // 通过 SESSIONID 去查找对应的 session
                Session session = list.stream().filter(s -> Objects.equals(this.sessionId, s.get("SESSIONID")))
                        .findFirst()
                        // 如果数据库没有 对应session，取 当前 session
                        .orElse(this);

                // 删除 指定的 session
                list.removeIf(s -> Objects.equals(this.sessionId,s.get("SESSIONID")));
                list.add(this);

            }
            // 序列化数据
            store.write(list);


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public Object getAttribute(String key){

        if(!check()) throw new RuntimeException("Session已过期");

        return this.get(key);
    }

    public void removeAttribute(String key){

        if(!check()) return;

        // 删除内存中，指定的key
        if("SESSIONID".equals(key)) throw new RuntimeException("删除失败");

        this.remove(key);

        try {
            List<Session> list = store.read();

            if(list == null || list.isEmpty()){
                return;
            }
            // 从 list 中，查找 对应的 session 是否存在
            // 通过 SESSIONID 去查找对应的 session
            Session session = list.stream().filter(s -> Objects.equals(this.sessionId, s.get("SESSIONID")))
                    .findFirst()
                    // 如果数据库没有 对应session，取 当前 session
                    .orElse(this);

            // 删除 指定的 session
            list.removeIf(s -> Objects.equals(this.sessionId,s.get("SESSIONID")));
            list.add(this);

            // 序列化数据
            store.write(list);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 销毁 session
     */
    public void invalidate(){

        // 删除 session 中的所有数据，同时，删除数据库数据
        //this.clear();
        // 从仓库读取数据
        try {
            List<Session> list = store.read();

            if(list == null || list.isEmpty()){
                return;
            }else {
                // 从 list 中，查找 对应的 session 是否存在

                // 通过 SESSIONID 去查找对应的 session
                Session session = list.stream().filter(s -> Objects.equals(this.sessionId, s.get("SESSIONID")))
                        .findFirst()
                        // 如果数据库没有 对应session，取 当前 session
                        .orElse(this);

                // 删除 指定的 session
                list.removeIf(s -> Objects.equals(this.sessionId,s.get("SESSIONID")));
            }
            // 序列化数据
            store.write(list);
            this.put("SESSIONID",sessionId);

        } catch (IOException e) {
            e.printStackTrace();
        }

        this.clear();

    }

    public boolean check(){
        int i = LocalDateTime.now().compareTo(expire);

        if(i > 0) invalidate();

        return i <= 0;

    }
}
